package com.gitee.wsl.ext.array

import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.jvm.JvmSynthetic

@OptIn(ExperimentalEncodingApi::class)
fun ByteArray.encodeBase64(startIndex: Int = 0, endIndex: Int = size) = Base64.encodeToByteArray(this,startIndex, endIndex)


@OptIn(ExperimentalEncodingApi::class)
fun ByteArray.encodeBase64ToString(startIndex: Int = 0, endIndex: Int = size) = Base64.encode(this,startIndex, endIndex)


@OptIn(ExperimentalEncodingApi::class)
fun ByteArray.decodeBase64(startIndex: Int = 0, endIndex: Int = size) = Base64.decode(this,startIndex, endIndex)

@OptIn(ExperimentalEncodingApi::class)
fun ByteArray.decodeBase64ToString(startIndex: Int = 0, endIndex: Int = size) = decodeBase64(startIndex, endIndex).decodeToString()

@JvmSynthetic
fun IntArray.byteEncode( bitSize: Int ): ByteArray {
    if(bitSize > UShort.SIZE_BITS)
        throw ArithmeticException("There are not enough bits to encode! Bit Size: $bitSize is too big!")

    val shorts = this

    val bits = BooleanArray(shorts.size * bitSize)

    for(i in shorts.indices)
        for(j in 0..<bitSize)
            bits[(i * bitSize) + j] = ((barrettReduce(shorts[i]) shr j) and 1) == 1

    return bits.bitsToBytes()
}

@JvmSynthetic
fun ByteArray.byteDecode( bitSize: Int ): IntArray {
    val byteArray = this
    val bits = byteArray.bytesToBits()
    val shorts = IntArray(bits.size / bitSize)
    for(i in shorts.indices)
        for(j in 0..<(bitSize))
            shorts[i] = shorts[i] + (bits[(i * bitSize) + j].int shl j)

    return shorts
}

fun ByteArray.singleByteDecode( ): IntArray {
    val bits = bytesToBits()
    val shorts = IntArray(bits.size)
    for(i in shorts.indices)
        shorts[i] = bits[i].int

    return shorts
}

@JvmSynthetic
internal fun barrettReduce(n: Int): Int {
    val q = (n * KyberConstants.BARRETT_APPROX) shr 26

    return n - (q * KyberConstants.Q)
}